package io.filecopy;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import util.Pair;

public class JobExecutor extends Thread implements JobPreparationListener {

  private JobDescription description;

  private PreparedJob job;

  private ProgressLogger progressLogger;

  private List<JobPreparationListener> jobPreparationListeners;

  public JobExecutor(JobDescription description) {
    this.problems = new ArrayList<Pair<FileSystemTask, IOException>>();
    jobPreparationListeners = new ArrayList<JobPreparationListener>();
    this.description = description;
    this.progressLogger = new ProgressLogger();
  }

  public void prepare() {
    synchronized (this) {
      this.job = description.prepare(this);
    }
  }

  public void addJobPreparationListener(JobPreparationListener listener) {
    jobPreparationListeners.add(listener);
  }

  public void removeJobPreparationListener(JobPreparationListener listener) {
    jobPreparationListeners.remove(listener);
  }

  private List<Pair<FileSystemTask, IOException>> problems;

  public PreparedJob getJob() {
    synchronized (this) {
      return job;
    }
  }

  public void run() {
    synchronized (this) {
      if (job == null) {
        prepare();
      }
    }
    try {
      while (job.hasMoreTasks()) {
        FileSystemTask task = job.getNextTask();
        try {
          task.execute(progressLogger);
        } catch (IOException ioe) {
          problems.add(new Pair<FileSystemTask, IOException>(task, ioe));
          ioe.printStackTrace();
        }
      }
    } catch (InterruptedException ie) {
      ie.printStackTrace();
    }
  }

  public ProgressLogger getProgressLogger() {
    return progressLogger;
  }

  public List<Pair<FileSystemTask, IOException>> getProblems() {
    return problems;
  }

  @Override
  public void jobInfoChanged(PreparedJob job) {
    for (int i = jobPreparationListeners.size() - 1; i >= 0; i--) {
      jobPreparationListeners.get(i).jobInfoChanged(job);
    }
  }

  @Override
  public void preparationCompleted(PreparedJob job) {
    for (int i = jobPreparationListeners.size() - 1; i >= 0; i--) {
      jobPreparationListeners.get(i).preparationCompleted(job);
    }
  }
}